package com.yz.jdd.webview.download;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebView;

import com.yz.jdd.base.MyApplication;
import com.yz.jdd.base.utils.BaseConfigs;
import com.yz.jdd.base.utils.IOUtils;
import com.yz.jdd.base.utils.LogUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Response;


public class H5DownFileUtils {

	public H5DownFileUtils() {
		creatFileDir(new File(_ZIP_FOLDERPATH));
		creatFileDir(new File(_UPZIP_FOLDERPATH));
		//creatFileDir(new File(Config.LOG_LOCATION));日志文件的处理 需要写。。。。。。。。。。。。
	}

//	public final static String sdDirRoot = Environment
//			.getExternalStorageDirectory().getPath();// 获取跟目录

	/**
	 * 在初始化的时候构建目录
	 */
	public final static String _ZIP_FOLDERPATH = MyApplication.application.getFilesDir().getAbsolutePath() + ""+"/zip/";
	/**
	 * 在初始化的时候构建目录
	 */
	public final static String _UPZIP_FOLDERPATH = MyApplication.application.getFilesDir().getAbsolutePath() + ""+"/unzip/";

	public final static String DEFAULT_FOLDERPATH=MyApplication.application.getFilesDir().getAbsolutePath()+"";


	/**
	 * 获取folderPath目录下所有文件路径
	 * 
	 * @param folderPath
	 * @return
	 */
	public File[] getHtml5File(File folderPath) {
		File[] files = folderPath.listFiles();
		return files;
	}

	/**
	 * 解压缩功能. 将zipFile文件解压到folderPath目录下. 测试的时候先把assets下的
	 * Zip文件放到sdcard/wo/目录下...
	 * 
	 * @throws Exception
	 */
	public static boolean upZipFile(File zipFile, String folderPath, String code) {
		ZipFile zfile;
		try {
			zfile = new ZipFile(zipFile);

			Enumeration zList = zfile.entries();
			ZipEntry ze = null;
			byte[] buf = new byte[1024];
			while (zList.hasMoreElements()) {
				ze = (ZipEntry) zList.nextElement();
				if (ze.isDirectory()) {
					String dirstr = folderPath + ze.getName();
					// dirstr.trim();
					dirstr = new String(dirstr.getBytes("8859_1"), "GB2312");
					File f = new File(dirstr);
					f.mkdir();
					continue;
				}
				OutputStream os = new BufferedOutputStream(
						new FileOutputStream(getRealFileName(folderPath,
								ze.getName(), code)));
				InputStream is = new BufferedInputStream(
						zfile.getInputStream(ze));
				int readLen = 0;
				while ((readLen = is.read(buf, 0, 1024)) != -1) {
					os.write(buf, 0, readLen);
				}
				is.close();
				os.close();
			}
			zfile.close();
			zipFile.delete();
			return true;
		} catch (ZipException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
	}

	public static File getRealFileName(String baseDir, String absFileName,
                                       String code) {
		String[] dirs = absFileName.split("/");
		if (!TextUtils.isEmpty(code) && dirs[0] != null
				&& !dirs[0].equals(code)) {
			dirs[0] = code;
		}
		File dr = new File(baseDir);
		if (!dr.exists()) {
			dr.mkdirs();
		}
		String lastDir = baseDir;
		if (dirs.length > 1) {
			for (int i = 0; i < dirs.length - 1; i++) {
				lastDir += (dirs[i] + "/");
				File dir = new File(lastDir);
				if (!dir.exists()) {
					dir.mkdirs();
				}
			}
			File ret = new File(lastDir, dirs[dirs.length - 1]);
			if (ret.isFile() && !ret.exists()) {
				try {
					ret.createNewFile();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			return ret;
		} else {
			return new File(baseDir, absFileName);
		}
	}

	/**
	 * 创建文件目录
	 * 
	 * @param file
	 */
	public static void creatFileDir(File file) {
		if (!file.exists()) {
			file.mkdirs();
		}
		Log.i("zx","absolute path"+file.getAbsolutePath());

	}



	/**
	 * 判断文件是否存在
	 * 
	 * @param url
	 * @return
	 */
	public static boolean isExists(String url) {
		if (TextUtils.isEmpty(url)) {
			return false;
		}
		File file = new File(url);
		return file.exists();
	}

	/**
	 * 递归删除文件和文件夹
	 * 
	 * @param file
	 *            要删除的根目录
	 */
	public static boolean deleteFile(File file) { // //
		boolean flag = true;
		if (file.exists() == false) {
			return flag;
		} else {
			if (file.isFile()) {
				flag = file.delete();
				return flag;
			} else {
				File[] childFile = file.listFiles();
				if (childFile == null || childFile.length == 0) {
					flag = file.delete();
					return flag;
				}
				for (File f : childFile) {
					deleteFile(f);
				}
				flag = file.delete();
				return flag;
			}
		}
		// return true;
	}

	/*
	 * Java文件操作 获取文件扩展名
	 */
	public static String getExtensionName(String filename) {
		if ((filename != null) && (filename.length() > 0)) {
			int dot = filename.lastIndexOf('.');
			if ((dot > -1) && (dot < (filename.length() - 1))) {
				return filename.substring(dot + 1);
			}
		}
		return filename;
	}
	public static void copyAssetsFile(Context context) throws IOException {
		String zipFilePath = H5DownFileUtils._ZIP_FOLDERPATH + BaseConfigs.assetsName;
		H5DownFileUtils h5DownFileUtils = new H5DownFileUtils();
		InputStream myInput;
		OutputStream myOutput = new FileOutputStream(zipFilePath);
		myInput = context.getAssets().open(BaseConfigs.assetsName);
		byte[] buffer = new byte[1024];
		int length = myInput.read(buffer);
		while (length > 0) {
			myOutput.write(buffer, 0, length);
			length = myInput.read(buffer);
		}
		myOutput.flush();
		myInput.close();
		myOutput.close();

		File zipFile = new File(zipFilePath);
		h5DownFileUtils.upZipFile(zipFile, H5DownFileUtils._UPZIP_FOLDERPATH, "");
	}

	public static final long ONE_KB = 1024;
	public static final long ONE_MB = ONE_KB * ONE_KB;
	/**
	 * The file copy buffer size (10 MB) （原为30MB，为更适合在手机上使用，将其改为10MB，by
	 * Geek_Soledad)
	 */
	private static final long FILE_COPY_BUFFER_SIZE = ONE_MB * 10;
	/**
	 * <p>
	 * 将一个目录下的文件全部拷贝到另一个目录里面，并且保留文件日期。
	 * </p>
	 * <p>
	 * 如果目标目录不存在，则被创建。 如果目标目录已经存在，则将会合并两个文件夹的内容，若有冲突则替换掉目标目录中的文件。
	 * </p>
	 *
	 * @param srcDir
	 *            源目录，不能为null且必须存在。
	 * @param destDir
	 *            目标目录，不能为null。
	 * @throws NullPointerException
	 *             如果源目录或目标目录为null。
	 * @throws IOException
	 *             如果源目录或目标目录无效。
	 * @throws IOException
	 *             如果拷贝中出现IO错误。
	 */
	public static void copyDirectoryToDirectory(File srcDir, File destDir)
			throws IOException {
		if (srcDir == null) {
			throw new NullPointerException("Source must not be null");
		}
		if (srcDir.exists() && srcDir.isDirectory() == false) {
			throw new IllegalArgumentException("Source '" + destDir
					+ "' is not a directory");
		}
		if (destDir == null) {
			throw new NullPointerException("Destination must not be null");
		}
		if (destDir.exists() && destDir.isDirectory() == false) {
			throw new IllegalArgumentException("Destination '" + destDir
					+ "' is not a directory");
		}
		copyDirectory(srcDir, new File(destDir, srcDir.getName()), true);
	}
	/**
	 * <p>
	 * 将目录及其以下子目录拷贝到一个新的位置，并且保留文件日期。
	 * <p>
	 * 如果目标目录不存在，则被创建。 如果目标目录已经存在，则将会合并两个文件夹的内容，若有冲突则替换掉目标目录中的文件。
	 * <p>
	 *
	 * @param srcDir
	 *            一个存在的源目录，不能为null。
	 * @param destDir
	 *            新的目录，不能为null。
	 *
	 * @throws NullPointerException
	 *             如果源目录或目标目录为null。
	 * @throws IOException
	 *             如果源目录或目标目录无效。
	 * @throws IOException
	 *             如果拷贝中出现IO错误。
	 */
	public static void copyDirectory(File srcDir, File destDir)
			throws IOException {
		copyDirectory(srcDir, destDir, true);
	}
	/**
	 * 拷贝目录到一个新的位置。
	 * <p>
	 * 该方法将拷贝指定的源目录的所有内容到一个新的目录中。
	 * </p>
	 * <p>
	 * 如果目标目录不存在，则被创建。 如果目标目录已经存在，则将会合并两个文件夹的内容，若有冲突则替换掉目标目录中的文件。
	 * </p>
	 *
	 * @param srcDir
	 *            一个存在的源目录，不能为null。
	 * @param destDir
	 *            新的目录，不能为null。
	 *
	 * @throws NullPointerException
	 *             如果源目录或目标目录为null。
	 * @throws IOException
	 *             如果源目录或目标目录无效。
	 * @throws IOException
	 *             如果拷贝中出现IO错误。
	 */
	public static void copyDirectory(File srcDir, File destDir,
									 boolean preserveFileDate) throws IOException {
		if (srcDir == null) {
			throw new NullPointerException("Source must not be null");
		}
		if (srcDir.exists() && srcDir.isDirectory() == false) {
			throw new IllegalArgumentException("Source '" + destDir
					+ "' is not a directory");
		}
		if (destDir == null) {
			throw new NullPointerException("Destination must not be null");
		}
		if (destDir.exists() && destDir.isDirectory() == false) {
			throw new IllegalArgumentException("Destination '" + destDir
					+ "' is not a directory");
		}
		if (srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) {
			throw new IOException("Source '" + srcDir + "' and destination '"
					+ destDir + "' are the same");
		}
		// 为满足当目标目录在源目录里面的情况。
		List<String> exclusionList = null;
		if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) {
			File[] srcFiles = srcDir.listFiles();
			if (srcFiles != null && srcFiles.length > 0) {
				exclusionList = new ArrayList<String>(srcFiles.length);
				for (File srcFile : srcFiles) {
					File copiedFile = new File(destDir, srcFile.getName());
					exclusionList.add(copiedFile.getCanonicalPath());
				}
			}
		}
		doCopyDirectory(srcDir, destDir, preserveFileDate, exclusionList);
	}
	/**
	 * Internal copy directory method.
	 *
	 * @param srcDir
	 *            the validated source directory, must not be <code>null</code>
	 * @param destDir
	 *            the validated destination directory, must not be
	 *            <code>null</code>
	 *
	 * @param preserveFileDate
	 *            whether to preserve the file date
	 * @param exclusionList
	 *            List of files and directories to exclude from the copy, may be
	 *            null
	 * @throws IOException
	 *             if an error occurs
	 * @since Commons IO 1.1
	 */
	private static void doCopyDirectory(File srcDir, File destDir,
										boolean preserveFileDate, List<String> exclusionList)
			throws IOException {
		// recurse
		File[] srcFiles = srcDir.listFiles();
		if (srcFiles == null) { // null if abstract pathname does not denote a
			// directory, or if an I/O error occurs
			throw new IOException("Failed to list contents of " + srcDir);
		}
		if (destDir.exists()) {
			if (destDir.isDirectory() == false) {
				throw new IOException("Destination '" + destDir
						+ "' exists but is not a directory");
			}
		} else {
			if (!destDir.mkdirs() && !destDir.isDirectory()) {
				throw new IOException("Destination '" + destDir
						+ "' directory cannot be created");
			}
		}
		if (destDir.canWrite() == false) {
			throw new IOException("Destination '" + destDir
					+ "' cannot be written to");
		}
		for (File srcFile : srcFiles) {
			File dstFile = new File(destDir, srcFile.getName());
			if (exclusionList == null
					|| !exclusionList.contains(srcFile.getCanonicalPath())) {
				if (srcFile.isDirectory()) {
					doCopyDirectory(srcFile, dstFile, preserveFileDate,
							exclusionList);
				} else {
					doCopyFile(srcFile, dstFile, preserveFileDate);
				}
			}
		}
		if (preserveFileDate) {
			destDir.setLastModified(srcDir.lastModified());
		}
	}
	/**
	 * @param srcFile
	 *            the validated source file, must not be <code>null</code>
	 * @param destFile
	 *            the validated destination file, must not be <code>null</code>
	 * @param preserveFileDate
	 *            whether to preserve the file date
	 * @throws IOException
	 *             if an error occurs
	 */
	private static void doCopyFile(File srcFile, File destFile,
								   boolean preserveFileDate) throws IOException {
		if (destFile.exists() && destFile.isDirectory()) {
			throw new IOException("Destination '" + destFile
					+ "' exists but is a directory");
		}
		FileInputStream fis = null;
		FileOutputStream fos = null;
		FileChannel input = null;
		FileChannel output = null;
		try {
			fis = new FileInputStream(srcFile);
			fos = new FileOutputStream(destFile);
			input = fis.getChannel();
			output = fos.getChannel();
			long size = input.size();
			long pos = 0;
			long count = 0;
			while (pos < size) {
				count = (size - pos) > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE
						: (size - pos);
				pos += output.transferFrom(input, pos, count);
			}
		} finally {
			IOUtils.closeQuietly(output);
			IOUtils.closeQuietly(fos);
			IOUtils.closeQuietly(input);
			IOUtils.closeQuietly(fis);
		}
		if (srcFile.length() != destFile.length()) {
			throw new IOException("Failed to copy full contents from '"
					+ srcFile + "' to '" + destFile + "'");
		}
		if (preserveFileDate) {
			destFile.setLastModified(srcFile.lastModified());
		}
	}
	/**
	 * @param file
	 *            the file to open for input, must not be <code>null</code>
	 * @return a new {@link FileInputStream} for the specified file
	 * @throws FileNotFoundException
	 *             if the file does not exist
	 * @throws IOException
	 *             if the file object is a directory
	 * @throws IOException
	 *             if the file cannot be read
	 * @since Commons IO 1.3
	 */
	public static FileInputStream openInputStream(File file) throws IOException {
		if (file.exists()) {
			if (file.isDirectory()) {
				throw new IOException("File '" + file
						+ "' exists but is a directory");
			}
			if (file.canRead() == false) {
				throw new IOException("File '" + file + "' cannot be read");
			}
		} else {
			throw new FileNotFoundException("File '" + file
					+ "' does not exist");
		}
		return new FileInputStream(file);
	}
	public static List<String> readLines(File file, String encoding)
			throws IOException {
		InputStream in = null;
		try {
			in = openInputStream(file);
			return readLines(in, encoding);
		} finally {
			IOUtils.closeQuietly(in);
		}
	}
	public static List<String> readLines(File file) throws IOException {
		return readLines(file, null);
	}
	/**
	 * @param input
	 *            the <code>InputStream</code> to read from, not null
	 * @return the list of Strings, never null
	 * @throws NullPointerException
	 *             if the input is null
	 * @throws IOException
	 *             if an I/O error occurs
	 * @since Commons IO 1.1
	 */
	public static List<String> readLines(InputStream input) throws IOException {
		InputStreamReader reader = new InputStreamReader(input);
		return readLines(reader);
	}
	public static List<String> readLines(InputStream input, String encoding)
			throws IOException {
		if (encoding == null) {
			return readLines(input);
		} else {
			InputStreamReader reader = new InputStreamReader(input, encoding);
			return readLines(reader);
		}
	}
	public static List<String> readLines(Reader input) throws IOException {
		BufferedReader reader = new BufferedReader(input);
		List<String> list = new ArrayList<String>();
		String line = reader.readLine();
		while (line != null) {
			list.add(line);
			line = reader.readLine();
		}
		return list;
	}

	/**
	 * 带进度文件下载
	 *
	 * @param fileUrl     文件url
	 * @param destFileDir 存储目标目录
	 */
	public static void downLoadFile(String fileUrl, final String destFileDir, final OnDownloadListener downloadListener) {
		final File file = new File(destFileDir);
		final okhttp3.Request request = new okhttp3.Request.Builder().url(fileUrl).build();
		OkHttpClient okHttpClient = new OkHttpClient().newBuilder().build();
		final Call call = okHttpClient.newCall(request);
		call.enqueue(new Callback() {
			@Override
			public void onFailure(Call call, IOException e) {
				if (downloadListener != null) {
					downloadListener.onError("Error: " + e);
				}
			}

			@Override
			public void onResponse(Call call, Response response) {
				InputStream is = null;
				byte[] buf = new byte[2048];
				int len = 0;
				FileOutputStream fos = null;
				try {
					long total = response.body().contentLength();
					Log.e("DownLoaderService", "total------>" + total);
					long current = 0;
					is = response.body().byteStream();
					fos = new FileOutputStream(file);
					while ((len = is.read(buf)) != -1) {
						current += len;
						fos.write(buf, 0, len);
//                        Log.e(TAG, "current------>" + current);
						long finalCurrent = current;
						int progress = (int) (100 * finalCurrent / total);
						LogUtils.i("下载进度: " + progress);
						if (downloadListener != null) {
							downloadListener.onProgress(progress);
						}
					}
					fos.flush();
					if (downloadListener != null) {
						downloadListener.onComplete();
					}
				} catch (IOException e) {
					if (downloadListener != null) {
						downloadListener.onError("Error: " + e);
					}
				} finally {
					try {
						if (is != null) {
							is.close();
						}
						if (fos != null) {
							fos.close();
						}
					} catch (IOException e) {
						Log.e("DownLoaderService", e.toString());
					}
				}
			}
		});
	}

	public interface OnDownloadListener {
		void onProgress(int progress);
		void onError(String errorMessage);
		void onComplete();
	}
}
